package com.jreque.persistance.memory;

import com.jreque.persistance.IQueuePersistance;
import java.util.*;
import com.jreque.queue.*;
import java.lang.*;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Persistonce model that keeps everything in memory.
 */
public class MemoryPersistance implements IQueuePersistance {
    /**
     */
    private HashMap<String,List<Integer>> queues;
    private HashMap<Integer, Task> tasks;
    private HashMap<String,HashMap<String,String>> settings;
    private HashMap<String,HashMap<String,Integer>> stats;
    private List<Task> inProgress;
    private int idSeq;

    public MemoryPersistance() {
        queues = new HashMap<String, List<Integer>>();
        tasks = new HashMap<Integer, Task>();
        settings = new HashMap<String, HashMap<String, String>>();
        stats = new HashMap<String, HashMap<String, Integer>>();
        inProgress = new ArrayList<Task>();
        idSeq = 0;
    }

    /**
     * @param task 
     * @return 
     */
    @Override
    public synchronized int enqueueTask(Task task) {
        int id = getNextId();
        tasks.put(id, task);
        String queueName = task.getQueueName();
        if(!queues.containsKey(queueName)) {
            queues.put(queueName, new Vector<Integer>());
        }
        queues.get(queueName).add(id);
        return id;
    }

    /**
     * @param queueName 
     * @param timeout 
     * @return 
     */
    public synchronized Task dequeueTask(String queueName, int timeout) {
        List<Integer> queue = queues.get(queueName);
        if(queue == null) return null;
        for(Integer i : queue) {
            Task t = tasks.get(i);
            if(t.getExecuteAfter() == null || t.getExecuteAfter().before(new Date())) {
                queue.remove(i);
                tasks.remove(i);
                inProgress.add(t);
                return t;
            }
        }
        return null;
    }

    /**
     * @param task 
     */
    public void completeTask(Task task) {
        inProgress.remove(task);
    }

    /**
     * @param taskID 
     * @return 
     */
    public synchronized boolean deleteTask(int taskID) {
        Task t = tasks.get(taskID);
        if(t == null) return false;
        tasks.remove(taskID);
        queues.get(t.getQueueName()).remove(Integer.valueOf(taskID));
        return true;
    }

    /**
     * @param queueName 
     * @return 
     */
    public synchronized HashMap getSettings(String queueName) {
        if(!settings.containsKey(queueName)) {
            settings.put(queueName, new HashMap<String, String>());
        }
        return settings.get(queueName);
    }

    /**
     * @param setting 
     * @param queueName 
     * @return 
     */
    public synchronized String getSetting(String queueName, String setting) {
        HashMap<String,String> map = (HashMap<String, String>)getSettings(queueName);
        return map.get(setting);
    }

    /**
     * @param setting 
     * @param value 
     * @param queueName 
     * @return 
     */
    public synchronized String addSetting(String queueName, String setting, String value) {
        HashMap<String,String> map = (HashMap<String, String>)getSettings(queueName);
        map.put(setting, value);
        return setting;
    }

    /**
     * @param queueName 
     * @return 
     */
    public HashMap getStats(String queueName) {
        if(!stats.containsKey(queueName)) {
            stats.put(queueName, new HashMap<String, Integer>());
        }
        return stats.get(queueName);
    }

    /**
     * @param statName 
     * @param value 
     * @param queueName 
     */
    public void incrementStat(String queueName, String statName, int value) {
        HashMap<String,Integer> map = (HashMap<String, Integer>)getStats(queueName);
        if(!map.containsKey(statName)) {
            map.put(statName, 0);
        }
        map.put(statName, map.get(statName) + value);
    }
    
    private synchronized int getNextId() {
        return ++idSeq;
    }
}

